import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';

import '../tabBar/kq_extended_tab_bar_view.dart';
import 'kq_size_reporting_widget.dart';

/// @author 高裕
/// 高度随子项改变的PageView
class KqExpandablePageView extends StatefulWidget {
  final List<Widget> children;

  final PageController? pageController;

  final ScrollPhysics? physics;

  final Function(int)? onPageChanged;

  /// 高度变化的动画时间
  final Duration? duration;

  /// ChildrenChange后的当前页，仅在内部无法获知当前页时传入，只会影响ChildrenChange后是否要赋值成0
  final int? currentPageWhenChildrenChange;

  /// cache page count
  /// default is 0.
  /// if cacheExtent is 1, it has two pages in cache
  /// null is infinity, it will cache all pages
  final int cacheExtent;

  /// 当 Scrollable 滚动未停止的时候，是默认阻止其内容获得 hittest， 这就会导致在快速切换 tab 的时候， 给人一种不能马上操作内容的感觉
  /// 将 ShouldIgnorePointerWhenScrolling 设置成false，这样的话 Scrollable 在滚动中也不会阻止内容获得 hittest。
  final bool shouldIgnorePointerWhenScrolling;

  /// {@macro flutter.widgets.scrollable.dragStartBehavior}
  final DragStartBehavior dragStartBehavior;

  /// {@macro flutter.material.Material.clipBehavior}
  ///
  /// Defaults to [Clip.hardEdge].
  final Clip clipBehavior;

  const KqExpandablePageView(
      {super.key,
      required this.children,
      this.pageController,
      this.physics,
      this.onPageChanged,
      this.duration,
      this.currentPageWhenChildrenChange,
      this.cacheExtent = 0,
      this.shouldIgnorePointerWhenScrolling = true,
      this.clipBehavior = Clip.hardEdge,
      this.dragStartBehavior = DragStartBehavior.start});

  @override
  State<KqExpandablePageView> createState() => _KqExpandablePageViewState();
}

class _KqExpandablePageViewState extends State<KqExpandablePageView>
    with TickerProviderStateMixin {
  late PageController _pageController;
  List<Widget> _oldChildren = [];
  List<HeightEntity> _heights = [];
  int _currentPage = 0; // 当前页
  double? nowSize; // 当前高度

  @override
  void initState() {
    super.initState();
    _heights = widget.children.map((e) => HeightEntity()).toList();
    if (_heights.isEmpty) {
      _heights = [HeightEntity()];
    }
    _oldChildren = widget.children;
    _pageController = (widget.pageController ?? PageController())
      ..addListener(() {
        final newPage = _pageController.page?.round();
        if (_currentPage != newPage && newPage != null) {
          setState(() {
            // onPageChanged的时机和currentPage改变的时机是不一致的
            _currentPage = newPage;
            if (_heights[_currentPage].isInit == false) {
              // 未初始化则提前赋值，防止高度变化过大，页面闪一下
              _heights[_currentPage].h = nowSize ?? _heights[0].h;
              _heights[_currentPage].isInit = true;
            }
          });
        }
      });
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_oldChildren.length != widget.children.length) {
      // 外部更改children
      _heights = widget.children.map((e) => HeightEntity()).toList();
      if (_heights.isEmpty) {
        _heights = [HeightEntity()];
      }
      _oldChildren = widget.children;
      _currentPage = widget.currentPageWhenChildrenChange ?? 0;
      // 未初始化则提前赋值，防止高度变化过大，页面闪一下
      _heights[_currentPage].h = nowSize ?? _heights[0].h;
    }
    return TweenAnimationBuilder<double>(
      curve: Curves.easeInOutCubic,
      duration: widget.duration ?? const Duration(milliseconds: 100),
      tween: Tween<double>(
          begin: nowSize ?? _heights[0].h, end: _heights[_currentPage].h),
      builder: (context, value, child) => SizedBox(height: value, child: child),
      onEnd: () {
        // 动画结束也赋值一次，因为pageChange不一定会触发
        nowSize = _heights[_currentPage].h;
      },
      child: KqExtendedPageView(
        physics: widget.physics,
        controller: _pageController,
        onPageChanged: (index) {
          nowSize = _heights[index].h;
          widget.onPageChanged?.call(index);
        },
        cacheExtent: widget.cacheExtent,
        shouldIgnorePointerWhenScrolling:
            widget.shouldIgnorePointerWhenScrolling,
        dragStartBehavior: widget.dragStartBehavior,
        clipBehavior: widget.clipBehavior,
        children: _sizeReportingChildren,
      ),
    );
  }

  List<Widget> get _sizeReportingChildren => widget.children
      .asMap()
      .map(
        (index, child) => MapEntry(
          index,
          OverflowBox(
            //这样父Widget就不会把自己的约束强加给子Widget，从而扭曲测量结果
            minHeight: 0,
            maxHeight: double.infinity,
            alignment: Alignment.topCenter,
            child: KqSizeReportingWidget(
              isReturnSameSize: true,
              onSizeChange: (size) {
                double height = size?.height ?? 0;
                if (height != _heights[index].h) {
                  setState(() {
                    _heights[index].h = height;
                    _heights[index].isInit = true;
                  });
                }
              },
              child: Align(child: child),
            ),
          ),
        ),
      )
      .values
      .toList();
}

class HeightEntity {
  HeightEntity({double? h, bool? isInit}) {
    this.h = h ?? 0;
    this.isInit = isInit ?? false;
  }

  double h = 0;

  bool isInit = false;
}
